package org.geeks.gsredisson.func;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

import org.geeks.gsredisson.GsRedissonApplicationTests;
import org.junit.Before;
import org.junit.Test;
import org.redisson.api.RBuckets;
import org.redisson.api.RCountDownLatch;
import org.redisson.api.RKeys;
import org.redisson.api.RList;
import org.redisson.api.RLock;
import org.redisson.api.RMap;
import org.redisson.api.RMultimap;
import org.redisson.api.RPermitExpirableSemaphore;
import org.redisson.api.RSemaphore;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.redisson.api.listener.MessageListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class RedissonT extends GsRedissonApplicationTests {

  @Autowired private RedissonClient redissonClient;

  private RBuckets rBuckets;

  private RKeys rKeys;

  private RList<Integer> rList;

  private RMap<String, Object> rMap;

  private RMultimap<String, List<String>> rMultimap;

  private RLock rLock;

  @Before
  public void before() {
    rBuckets = redissonClient.getBuckets(org.redisson.client.codec.StringCodec.INSTANCE);
    rKeys = redissonClient.getKeys();
    rList = redissonClient.getList("RList");
    rMap = redissonClient.getMap("RMap");
    rMultimap = redissonClient.getSetMultimap("RMultimap");

    rLock = redissonClient.getLock("RLock");
  }

  @Test
  public void rBucketsT() {
    String key = "xx";
    String value = "oo";

    rBuckets.set(ImmutableMap.of(key, value));

    Assert.isTrue(value.equals(rBuckets.get("xx").get("xx")), key + "` value is wrong");

    rKeys.delete(key);

    Assert.isNull(rBuckets.get("xx").get("xx"), key + " is not null");
  }

  @Test
  public void rListT() {
    IntStream.range(0, 7)
        .forEach(
            i -> {
              rList.add(i);
            });

    log.info("{}", rList);
  }

  @Test
  public void rMapT() {
    rMap.put("age", 17);

    log.info("{}", rMap.get("age"));
  }

  @Test
  public void rMultimapT() {
    String key = "L0";

    log.info("RMultimap, {}", rMultimap.get(key));

    rMultimap.put(key, Lists.newArrayList("V-0", "V-1"));

    log.info("RMultimap, {}", rMultimap.get(key));
  }

  @Test
  public void rLockT() {
    try {
      if (rLock.tryLock()) {
        log.info("Get lock, Thread id is {}", Thread.currentThread().getId());
      }
    } finally {
      rLock.unlock();
    }
  }

  @Test
  public void rCountDownLatchCountDown() throws Exception {
    RCountDownLatch latch = redissonClient.getCountDownLatch("anyCountDownLatch");

    latch.countDown();
  }

  @Test
  public void rCountDownLatch() throws Exception {
    RCountDownLatch latch = redissonClient.getCountDownLatch("anyCountDownLatch");

    latch.trySetCount(1);

    latch.await();

    log.info("Execute logic ~");
  }

  @Test
  public void rSemaphore() throws Exception {
    RSemaphore semaphore = redissonClient.getSemaphore("semaphore");
    semaphore.trySetPermits(7);

    semaphore.release(7);

    log.info("Available permits is {}", semaphore.availablePermits());

    while (semaphore.tryAcquire(1000, TimeUnit.MILLISECONDS)) {
      log.info("Permits left {}", semaphore.availablePermits());

      new Thread(
              () -> {
                log.info("Get permits ~");
                try {
                  Thread.sleep(1000);
                } catch (InterruptedException e) {
                  e.printStackTrace();
                }

                semaphore.release();
              })
          .start();
    }

    log.info("No permits available ~");
  }

  @Test
  public void rPermitExpirableSemaphore() throws Exception {
    RPermitExpirableSemaphore semaphore = redissonClient.getPermitExpirableSemaphore("mySemaphore");
    semaphore.trySetPermits(7);

    log.info("Available permits is {}", semaphore.availablePermits());

    while (semaphore.tryAcquire(0, 2, TimeUnit.MILLISECONDS) != null) {
      log.info("Get permits ~");
    }

    log.info("no permits available ~");
  }

  @Test
  public void publish() {
    RTopic topic = redissonClient.getTopic("anyTopic");

    topic.publish("Hello, world");
  }

  @Test
  public void subscribe() throws Exception {
    RTopic topic = redissonClient.getTopic("anyTopic");

    topic.addListener(
        String.class,
        new MessageListener<String>() {
          @Override
          public void onMessage(CharSequence channel, String msg) {
            log.info("Receive msg : {}", msg);
          }
        });

    Thread.currentThread().join();
  }
}
